package SVN::TeamTools::Plugins::Mailer;

use warnings;
use strict;
use Carp;
use Error qw(:try);

use SVN::TeamTools::Store::Config;

use HTML::Template;
use CGI;
use URI::Escape;
use Data::Dumper;
use Net::SMTP;
use Net::SMTP::TLS;

use DBI;

my $conf;
my $logger;
BEGIN { $conf = SVN::TeamTools::Store::Config->new(); $logger = $conf->{logger}; }

sub hasAction {
	shift;
	my %args	= @_;
	my $action	= $args{action};
	return ("|dsp.config|dsp.userconfig|get.mailer.userconf|set.mailer.userconf|test.mailer.mailaddress|proc.hook.post-commit|" =~ /\|\Q$action\E\|/);
}

sub getTemplate {
	shift;
	my %args	= @_;
	my $action	= $args{action};
	my $cgi		= $args{cgi};
	my $template;
	if ($action eq "dsp.config") {
		$template = HTML::Template->new( filename => 'SVN/TeamTools/Plugins/tmpl/mailer-config.tmpl', path => @INC );
	} elsif ($action eq "dsp.userconfig") {
		$template = HTML::Template->new( filename => 'SVN/TeamTools/Plugins/tmpl/mailer-userconfig.tmpl', path => @INC );
		$template->param (p_uname=>$ENV{REMOTE_USER});
	}

	return $template;
}

sub procHook {
	shift;
	my %args	= @_;
	my $action	= $args{action};
	my $param	=$args{param};

	## Commit alerts
	if ($action =~ /proc.hook.post-commit/) {
		my $mailer	= SVN::TeamTools::Plugins::Mailer->new();
		my $repopath    = $param->[0];
		my $rev         = $param->[1];
                my $repo = SVN::TeamTools::Store::Repo->new();
		my $look = $repo->getLook(rev=>$rev);
		my $stmnt = "SELECT a.mailaddress, r.mailrule, r.targettype FROM mailusers a, mailrules r WHERE r.username=a.username";
		my %mqueue;

		$logger->info("Starting alert tests");


		try {
			my $sth = $mailer->{dbh}->prepare($stmnt); $sth->execute();
			while (my ($mailaddress,$mailrule,$targettype) = $sth->fetchrow()) {
				$logger->info ("Checking for $mailaddress, $mailrule, $targettype");
				my $msg;
				if ($targettype =~ /Message/) {
					if ( $look->log_msg() =~ m#$mailrule#) {
						$msg=$msg . "Revision's commit message matched rule ($mailrule)\n";
					}
				} else {
					foreach my $path ($look->changed()) {
						if ($path =~ m#$mailrule#) {
							$msg=$msg . "Path ($path) matched rule ($mailrule)\n";
						}
					}
				}
				if ($msg) {
					if (exists $mqueue{$mailaddress}) {
						$mqueue{$mailaddress}=$mqueue{$mailaddress} . $msg;
					} else {
						$mqueue{$mailaddress}=$msg;
					}
				}
			}
		} otherwise {
			my $exc = shift; croak "Error fetching data,  error: $exc";
		};

		# Mail results (if any)
		foreach my $addr ( keys %mqueue ) {
			$logger->info ("Alerts for $addr");
			$mailer->sendMail(recipients=>[$addr], subject=>'SVN alerts for revision '.$rev, message=>$mqueue{$addr});
		}
	}
}

				
sub getData {
	shift;
	my %args	= @_;
	my $action      = $args{action};
	my $param       = $args{param};
	my $uname	= $ENV{REMOTE_USER};

	my $mailer	= SVN::TeamTools::Plugins::Mailer->new();

	if ($action =~ /get.mailer.userconf/) {
		my $mailaddress	= "";
		my @rules;
		
		my $stmnt = "	SELECT mailaddress FROM mailusers WHERE username='$uname'";
		try {
			my $sth = $mailer->{dbh}->prepare($stmnt); $sth->execute();
			($mailaddress) = $sth->fetchrow();
			if (! $mailaddress) {
				$mailaddress="";
			}
		} otherwise {
			my $exc = shift; croak "Error fetching data,  error: $exc";
		};

		$stmnt = "	SELECT mailrule, targettype FROM mailrules WHERE username='$uname'";
		try {
			my $sth = $mailer->{dbh}->prepare($stmnt); $sth->execute();
			while (my ($mailrule,$targettype) = $sth->fetchrow()) {
				push (@rules, {mailrule=>$mailrule, targettype=>$targettype});
			}
		} otherwise {
			my $exc = shift; croak "Error fetching data,  error: $exc";
		};
		my %result = (mailaddress=>$mailaddress, mailrules=>\@rules);
		return \%result;
	} elsif ($action =~ /set.mailer.userconf/) {
		my $stmnt = "	DELETE FROM mailrules WHERE username='$uname'";
		$mailer->{dbh}->do($stmnt);

		$stmnt = "	DELETE FROM mailusers WHERE username='$uname'";
		$mailer->{dbh}->do($stmnt);

		$stmnt = "	INSERT INTO mailusers (username, mailaddress) VALUES ('$uname','$param->{mailaddress}')";
		$mailer->{dbh}->do($stmnt);

		foreach my $rule (@{$param->{mailrules}}) {
			if (defined $rule) {
				$stmnt = "	INSERT INTO mailrules (username, mailrule, targettype) VALUES ('$uname','$rule->{mailrule}','$rule->{targettype}')";
				$mailer->{dbh}->do($stmnt);
			}
		}

		my %result = (msg => "Stored");
		return \%result;
	} elsif ($action =~ /test.mailer.mailaddress/) {
		$mailer->sendMail(recipients=>[$param->{address}], subject=>'SVN mail address test', message=>'This is generated messages to test the validity of this email address. A reply is not needed.');
		return [];
	}
}
# Constructor
sub new {
	my $class	= shift;
	my %args	= @_;
	my $create	= $args{create};

	my $self = {};
	try {
		$self = {
			dbh => DBI->connect("dbi:SQLite:dbname=" . $conf->{config}->{mailer}->{maildb},"",""),
		};
	} otherwise {
		my $exc = shift;
		croak "Error opening database with path $conf->{config}->{mailer}->{maildb} error: $exc";
	};
       if ($create) {
		try {
			$self->{dbh}->do("DROP TABLE IF EXISTS mailusers");
			$self->{dbh}->do("CREATE TABLE mailusers (id INTEGER PRIMARY KEY, username TEXT, mailaddress TEXT)");
			$self->{dbh}->do("CREATE UNIQUE INDEX mailusers_idx1 ON mailusers(username)");
 
			$self->{dbh}->do("DROP TABLE IF EXISTS mailrules");
			# Targettype can be Path or Message
			$self->{dbh}->do("CREATE TABLE mailrules (id INTEGER PRIMARY KEY, username TEXT, mailrule TEXT, targettype TEXT)");
			$self->{dbh}->do("CREATE INDEX mailrules_idx1 ON mailrules(username)");
		} otherwise {
			my $exc = shift;
			croak "Error creating tables structure,  error: $exc";
		};
	}
	bless $self, $class;
	return $self;
}


# Send a mail message ($subject, @recipients, $message)
sub sendMail {
	my $self	= shift;
	my %args	= @_;
	my $mailer	= $conf->{config}->{mailer};
	my $smtp;

	my $message = HTML::Template->new ( filename => 'SVN/TeamTools/Plugins/tmpl/mailer-message.tmpl', path => \@INC );
	$message->param(p_subject	=> $args{subject});
	$message->param(p_message	=> $args{message});
	if ( defined $mailer->{mailauth} and $mailer->{mailauth} eq 1 ) {
		$smtp = Net::SMTP::TLS->new($mailer->{mailrelayhost}, 
				Hello 		=> $mailer->{maildomain}, 
				User		=>$mailer->{mailusername},
				Password	=>$mailer->{mailpassword}
		) or die "Could not contact SMTP mail server";
	} else {
		$smtp = Net::SMTP->new($mailer->{mailrelayhost}, Hello => $mailer->{maildomain}) or die "Could not contact SMTP mail server";
	}
	if (! $smtp->mail ($mailer->{mailsender})) {
		die "Could not set mail sender";
	}
	foreach my $address (@{$args{recipients}}) {
		$logger->info("Sending mail to $address");
		if (! $smtp->recipient ( $address , { SkipBad => 1})) {
			die "Could not set recipients";
		}
	}
	if (! $smtp->data ([$message->output()])) {
		die "Could not set mail content";
	}
	$smtp->quit();
}
1;
